home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / m4-1_0_3.lha / m4-1.0.3 / format.c < prev    next >
C/C++ Source or Header  |  1992-12-19  |  14KB  |  690 lines

  1. /*
  2.  * GNU m4 -- A simple macro processor
  3.  * Copyright (C) 1989-1992 Free Software Foundation, Inc.
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /*
  21.  * printf like formatting for m4.
  22.  */
  23.  
  24. #include "m4.h"
  25.  
  26. #ifdef HAVE_EFGCVT
  27. /*
  28.  * Various constants for floating point formatting.
  29.  */
  30. #define MAXFIELD    128    /* size of buffer for formatted text */
  31. /* The following two are hardware dependant .  */
  32. #define ECVTMAX        18    /* max number of significant digits for %e */
  33. #define FCVTMAX        (18+38+4) /* max number of significant digits for %f */
  34.  
  35. /*
  36.  * Externs used herein.
  37.  */
  38. #if HAVE_EFGCVT <= 1
  39. extern char *ecvt (), *fcvt (), *gcvt ();
  40. #endif
  41.  
  42. #ifndef STDC_HEADERS
  43. extern int atoi ();
  44. extern long atol ();
  45. extern double atof ();
  46. #endif /* STDC_HEADERS */
  47.  
  48. #define min(a, b)    ((a) < (b) ? (a) : (b))
  49.  
  50. static char const digits[] = "0123456789abcdef";
  51. static char const Digits[] = "0123456789ABCDEF";
  52.  
  53. /* STR has dimension MAXFIELD (?).  */
  54.  
  55. static char *
  56. ulong_to_str (register unsigned long val, char *str, int base,
  57.           const char *digits)
  58. {
  59.   register char *s = &str[MAXFIELD];
  60.  
  61.   *--s = '\0';
  62.   do
  63.     {
  64.       *--s = digits[val % base];
  65.       val /= base;
  66.     }
  67.   while (val > 0);
  68.  
  69.   return s;
  70. }
  71.  
  72. /* Clear trailing zeroes, return argument.  */
  73.  
  74. static char *
  75. clr0 (char *s)
  76. {
  77.   register char *t;
  78.  
  79.   for (t = s + strlen (s); *--t == '0' && t > s;)
  80.     *t = '\0';
  81.   return s;
  82. }
  83. #else /* HAVE_EFGCVT */
  84.  
  85. union values
  86. {
  87.   int v_int;
  88.   unsigned int v_uint;
  89.   long v_long;
  90.   unsigned long v_ulong;
  91.   double v_double;
  92.   char *v_str;
  93. };
  94.  
  95. #endif /* HAVE_EFGCVT */
  96.  
  97. /*
  98.  * Simple varargs substitute.
  99.  */
  100.  
  101. #define ARG_INT(argc, argv) \
  102.     ((argc == 0) ? 0 : \
  103.      (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
  104.  
  105. #define ARG_UINT(argc, argv) \
  106.     ((argc == 0) ? 0 : \
  107.      (--argc, argv++, (unsigned int) atoi (TOKEN_DATA_TEXT (argv[-1]))))
  108.  
  109. #define ARG_LONG(argc, argv) \
  110.     ((argc == 0) ? 0 : \
  111.      (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
  112.  
  113. #define ARG_ULONG(argc, argv) \
  114.     ((argc == 0) ? 0 : \
  115.      (--argc, argv++, (unsigned long) atol (TOKEN_DATA_TEXT (argv[-1]))))
  116.  
  117. #define ARG_STR(argc, argv) \
  118.     ((argc == 0) ? "" : \
  119.      (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
  120.  
  121. #define ARG_DOUBLE(argc, argv) \
  122.     ((argc == 0) ? 0 : \
  123.      (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
  124.  
  125.  
  126.  
  127.  
  128. /*
  129.  * The main formatting function.  Output is placed on the obstack OBS,
  130.  * the first argument in ARGV is the formatting string, and the rest is
  131.  * arguments for the string.
  132.  */
  133. void
  134. format (struct obstack *obs, int argc, token_data **argv)
  135. {
  136. #ifdef HAVE_EFGCVT
  137.   char *fmt;
  138.   int c;            /* a simple character */
  139.   char fc;            /* format code */
  140.  
  141.   /* Flags.  */
  142.   char flags;            /* 1 iff treating flags */
  143.   char ljust;            /* left justification */
  144.   char mandsign;        /* mandatory sign */
  145.   char noplus;            /* use space if no sign */
  146.   char alternate;        /* use alternate form */
  147.   char zeropad;            /* do zero padding */
  148.   char plus;            /* plus-sign, according to mandatory and noplus */
  149.  
  150.   /* Precision specifiers.  */
  151.   int width;            /* minimum field width */
  152.   int prec;            /* precision */
  153.   int maxch;            /* maximum no. of chars to print */
  154.   char lflag;            /* long flag */
  155.   char hflag;            /* short flag */
  156.  
  157.   /* Different parts of each specification.  */
  158.   char sign;            /* wanted sign, iff any */
  159.   int ppad;            /* pre-prefix zero padding */
  160.   char *prefix;            /* value prefix */
  161.   int lpad;            /* zero padding on the left */
  162.   register char *s;        /* ptr to formatted text */
  163.   int rpad;            /* zero padding on the rigth*/
  164.   char *suffix;            /* value suffix */
  165.  
  166.   /* Buffer and stuff.  */
  167.   char str[MAXFIELD];        /* buffer for formatted text */
  168.   int length;            /* length of str */
  169.   int padding;            /* padding at the left or rigth */
  170.   register int i;        /* an index */
  171.  
  172. /* Length of trailing string in str.  */
  173. #define LENGTH(s)    (&str[MAXFIELD-1] - (s))
  174. #define HAS_SIGN    (sign != '\0')
  175.  
  176.   fmt = ARG_STR (argc, argv);
  177.   for (;;)
  178.     {
  179.       while ((c = *fmt++) != '%')
  180.     {
  181.       if (c == 0)
  182.         return;
  183.       obstack_1grow (obs, c);
  184.     }
  185.       if (*fmt == '%')
  186.     {
  187.       obstack_1grow (obs, '%');
  188.       fmt++;
  189.       continue;
  190.     }
  191.  
  192.       /* Parse flags.  */
  193.       flags = 1;
  194.       ljust = mandsign = noplus = alternate = zeropad = 0;
  195.       do
  196.     {
  197.       switch (*fmt)
  198.         {
  199.         case '-':        /* left justification */
  200.           ljust = 1;
  201.           break;
  202.         case '+':        /* mandatory sign */
  203.           mandsign = 1;
  204.           break;
  205.         case ' ':        /* space instead of positive sign */
  206.           noplus = 1;
  207.           break;
  208.         case '0':        /* zero padding */
  209.           zeropad = 1;
  210.           break;
  211.         case '#':        /* alternate output */
  212.           alternate = 1;
  213.           break;
  214.         default:
  215.           flags = 0;
  216.           break;
  217.         }
  218.     }
  219.       while (flags && fmt++);
  220.  
  221.       plus = '\0';        /* what to use as a plus ??? */
  222.       if (mandsign)
  223.     plus = '+';
  224.       else if (noplus)
  225.     plus = ' ';
  226.  
  227.       if (ljust)
  228.     zeropad = 0;
  229.  
  230.       /* Minimum field width.  */
  231.       width = -1;
  232.       if (*fmt == '*')
  233.     {
  234.       width = ARG_INT (argc, argv);
  235.       fmt++;
  236.     }
  237.       else if (isdigit (*fmt))
  238.     {
  239.       width = 0;
  240.       do
  241.         {
  242.           width = width * 10 + *fmt++ - '0';
  243.         }
  244.       while (isdigit (*fmt));
  245.     }
  246.  
  247.       /* Maximum precision.  */
  248.       prec = -1;
  249.       if (*fmt == '.')
  250.     {
  251.       if (*(++fmt) == '*')
  252.         {
  253.           prec = ARG_INT (argc, argv);
  254.           ++fmt;
  255.         }
  256.       else if (isdigit (*fmt))
  257.         {
  258.           prec = 0;
  259.           do
  260.         {
  261.           prec = prec * 10 + *fmt++ - '0';
  262.         }
  263.           while (isdigit (*fmt));
  264.         }
  265.     }
  266.  
  267.       /* Length modifiers.  */
  268.       lflag = (*fmt == 'l');
  269.       hflag = (*fmt == 'h');
  270.       if (lflag || hflag)
  271.     fmt++;
  272.  
  273.       sign = '\0';
  274.       ppad = lpad = rpad = 0;
  275.       maxch = -1;
  276.       prefix = suffix = "";
  277.  
  278.       switch (fc = *fmt++)
  279.     {
  280.  
  281.     case '\0':
  282.       return;
  283.  
  284.     case 'c':
  285.       c = ARG_INT (argc, argv);
  286.       str[0] = (unsigned char) c;
  287.       str[1] = '\0';
  288.       s = str;
  289.       break;
  290.  
  291.     case 's':
  292.       s = ARG_STR (argc, argv);
  293.       maxch = prec;
  294.       break;
  295.  
  296.     case 'd':
  297.     case 'i':
  298.       if (lflag)
  299.         {
  300.           long val = ARG_LONG (argc, argv);
  301.           if (val < 0)
  302.         {
  303.           val = -val;    /* doesn't work for MINLONG */
  304.           sign = '-';
  305.         }
  306.           else
  307.         sign = plus;
  308.           s = ulong_to_str ((unsigned long) val, str, 10, digits);
  309.         }
  310.       else
  311.         {
  312.           int val = ARG_INT (argc, argv);
  313.           if (hflag)
  314.         val = (short) val;
  315.           if (val < 0)
  316.         {
  317.           val = -val;    /* doesn't work for MININT */
  318.           sign = '-';
  319.         }
  320.           else
  321.         sign = plus;
  322.           s = ulong_to_str ((unsigned long) val, str, 10, digits);
  323.         }
  324.       if (zeropad)
  325.         lpad = width - LENGTH (s) - HAS_SIGN;
  326.       break;
  327.  
  328.     case 'o':
  329.       if (lflag)
  330.         {
  331.           unsigned long val = ARG_ULONG (argc, argv);
  332.           s = ulong_to_str ((unsigned long) val, str, 8, digits);
  333.         }
  334.       else
  335.         {
  336.           unsigned int val = ARG_UINT (argc, argv);
  337.           if (hflag)
  338.         val = (unsigned short) val;
  339.           s = ulong_to_str ((unsigned long) val, str, 8, digits);
  340.         }
  341.       if (alternate)
  342.         prefix = "0";
  343.       if (zeropad)
  344.         lpad = width - LENGTH (s) - alternate;
  345.       break;
  346.  
  347.     case 'x':
  348.     case 'X':
  349.       if (lflag)
  350.         {
  351.           unsigned long val = ARG_ULONG (argc, argv);
  352.           s = ulong_to_str ((unsigned long) val, str, 16,
  353.                    (fc == 'x') ? digits : Digits);
  354.         }
  355.       else
  356.         {
  357.           unsigned int val = ARG_UINT (argc, argv);
  358.           if (hflag)
  359.         val = (unsigned short) val;
  360.           s = ulong_to_str ((unsigned long) val, str, 16,
  361.                    (fc == 'x') ? digits : Digits);
  362.         }
  363.       if (alternate)
  364.         prefix = (fc == 'X') ? "0X" : "0x";
  365.       if (zeropad)
  366.         lpad = width - LENGTH (s) - 2*alternate;
  367.       break;
  368.  
  369.     case 'u':
  370.       if (lflag)
  371.         {
  372.           unsigned long val = ARG_ULONG (argc, argv);
  373.           s = ulong_to_str ((unsigned long) val, str, 10, digits);
  374.         }
  375.       else
  376.         {
  377.           unsigned int val = ARG_UINT (argc, argv);
  378.           if (hflag)
  379.         val = (unsigned short) val;
  380.           s = ulong_to_str ((unsigned long) val, str, 10, digits);
  381.         }
  382.       if (zeropad)
  383.         lpad = width - LENGTH (s);
  384.       break;
  385.  
  386.     case 'e':
  387.     case 'E':
  388.       {
  389.         char *t;
  390.         int sgn, decpt, exp, n;
  391.         double val = ARG_DOUBLE (argc, argv);
  392.  
  393.         if (prec < 0)
  394.           prec = 6;
  395.         t = clr0 (ecvt (val, min (prec + 1, ECVTMAX), &decpt, &sgn));
  396.         sign = sgn ? '-' : plus;
  397.  
  398.         n = prec;
  399.         s = str;
  400.         exp = (t[0] == '0' && t[1] == '\0') ? 0 : decpt - 1;
  401.  
  402.         *s++ = *t++;
  403.         if (n > 0 || alternate)
  404.           *s++ = '.';
  405.         while (*t != '\0' && --n >= 0)
  406.           *s++ = *t++;
  407.         *s = '\0';
  408.         rpad = n;
  409.  
  410.         sgn = 0;
  411.         if (exp < 0)
  412.           {
  413.         exp = -exp;
  414.         sgn = 1;
  415.           }
  416.         t = ulong_to_str ((unsigned long) exp, str, 10, digits);
  417.         if (exp < 10)
  418.           *--t = '0';    /* always at least two digits */
  419.         *--t = sgn ? '-' : '+';
  420.         *--t = fc;
  421.  
  422.         if (zeropad)
  423.           {
  424.         lpad = width - HAS_SIGN - (s - str) - LENGTH (t);
  425.         if (rpad > 0)
  426.           lpad -= rpad;
  427.           }
  428.  
  429.         suffix = t;
  430.         s = str;
  431.       }
  432.       break;
  433.  
  434.     case 'f':
  435.       {
  436.         char *t;
  437.         int sgn, decpt, n;
  438.         double val = ARG_DOUBLE (argc, argv);
  439.  
  440.         if (prec < 0)
  441.           prec = 6;
  442.  
  443.         t = clr0 (fcvt (val, min (prec, FCVTMAX), &decpt, &sgn));
  444.  
  445.         sign = sgn ? '-' : plus;
  446.  
  447.         n = prec;
  448.         s = str;
  449.  
  450.         if (decpt <= 0)
  451.           {
  452.         prefix = (n > 0 || alternate) ? "0." : "0";
  453.         lpad = min (-decpt, prec);
  454.         n -= lpad;
  455.           }
  456.         else
  457.           {
  458.         while (--decpt >= 0)
  459.           *s++ = *t++;
  460.         if (n > 0 || alternate)
  461.           *s++ = '.';
  462.           }
  463.         while (*t && --n >= 0)
  464.           *s++ = *t++;
  465.  
  466.         *s = '\0';
  467.         rpad = n;
  468.  
  469.         if (zeropad)
  470.           ppad = width - HAS_SIGN - (prefix[1] ? 2 : 1) - lpad -
  471.         (s - str) - rpad;
  472.  
  473.         s = str;
  474.       }
  475.       break;
  476.  
  477.     default:
  478.       continue;
  479.     }
  480.  
  481.       if (lpad < 0)
  482.     lpad = 0;
  483.       if (rpad < 0)
  484.     rpad = 0;
  485.       if (width < 0)
  486.     width = 0;
  487.  
  488.       i = strlen (s);
  489.       if (maxch <= 0 || maxch > i)
  490.     maxch = i;
  491.  
  492.       length = (HAS_SIGN + ppad + strlen (prefix) + lpad + maxch
  493.         + rpad + strlen (suffix));
  494.       padding = 0;
  495.       if (width != 0)
  496.     {
  497.       padding = width - length;
  498.     }
  499.  
  500.       if (ljust == 0)        /* left padding */
  501.     for (i = padding; --i >= 0;)
  502.       obstack_1grow (obs, ' ');
  503.       if (HAS_SIGN)        /* sign */
  504.     obstack_1grow (obs, sign);
  505.       for (i = ppad; --i >= 0;)    /* pre-prefix zero padding */
  506.     obstack_1grow (obs, '0');
  507.       for (; *prefix; ++prefix)    /* prefix */
  508.     obstack_1grow (obs, *prefix);
  509.       for (i = lpad; --i >= 0;)    /* left zero padding */
  510.     obstack_1grow (obs, '0');
  511.       for (i = maxch; --i >= 0; ++s) /* actual text */
  512.     obstack_1grow (obs, *s);
  513.       for (i = rpad; --i >= 0;)    /* right zero padding */
  514.     obstack_1grow (obs, '0');
  515.       for (; *suffix; ++suffix)    /* suffix */
  516.     obstack_1grow (obs, *suffix);
  517.       if (ljust != 0)        /* right padding */
  518.     for (i = padding; --i >= 0;)
  519.       obstack_1grow (obs, ' ');
  520.     }
  521.   /* NOTREACHED */
  522.  
  523. #else                /* HAVE_EFGCVT */
  524.  
  525.   char *fmt;
  526.   char *fstart;            /* beginning of current format spec */
  527.   int c;            /* a simple character */
  528.  
  529.   /* Flags.  */
  530.   char flags;            /* 1 iff treating flags */
  531.  
  532.   /* Precision specifiers.  */
  533.   int width;            /* minimum field width */
  534.   int prec;            /* precision */
  535.   char lflag;            /* long flag */
  536.   char hflag;            /* short flag */
  537.  
  538.   /* Buffer and stuff.  */
  539.   char str[256];        /* buffer for formatted text */
  540.   union values val;
  541.  
  542.   fmt = ARG_STR (argc, argv);
  543.   for (;;)
  544.     {
  545.       while ((c = *fmt++) != '%')
  546.     {
  547.       if (c == 0)
  548.         return;
  549.       obstack_1grow (obs, c);
  550.     }
  551.  
  552.       fstart = fmt - 1;
  553.  
  554.       if (*fmt == '%')
  555.     {
  556.       obstack_1grow (obs, '%');
  557.       fmt++;
  558.       continue;
  559.     }
  560.  
  561.       /* Parse flags.  */
  562.       flags = 1;
  563.       do
  564.     {
  565.       switch (*fmt)
  566.         {
  567.         case '-':        /* left justification */
  568.         case '+':        /* mandatory sign */
  569.         case ' ':        /* space instead of positive sign */
  570.         case '0':        /* zero padding */
  571.         case '#':        /* alternate output */
  572.           break;
  573.         default:
  574.           flags = 0;
  575.           break;
  576.         }
  577.     }
  578.       while (flags && fmt++);
  579.  
  580.       /* Minimum field width.  */
  581.       width = -1;
  582.       if (*fmt == '*')
  583.     {
  584.       width = ARG_INT (argc, argv);
  585.       fmt++;
  586.     }
  587.       else if (isdigit (*fmt))
  588.     {
  589.       do
  590.         {
  591.           fmt++;
  592.         }
  593.       while (isdigit (*fmt));
  594.     }
  595.  
  596.       /* Maximum precision.  */
  597.       prec = -1;
  598.       if (*fmt == '.')
  599.     {
  600.       if (*(++fmt) == '*')
  601.         {
  602.           prec = ARG_INT (argc, argv);
  603.           ++fmt;
  604.         }
  605.       else if (isdigit (*fmt))
  606.         {
  607.           do
  608.         {
  609.           fmt++;
  610.         }
  611.           while (isdigit (*fmt));
  612.         }
  613.     }
  614.  
  615.       /* Length modifiers.  */
  616.       lflag = (*fmt == 'l');
  617.       hflag = (*fmt == 'h');
  618.       if (lflag || hflag)
  619.     fmt++;
  620.  
  621.       switch (*fmt++)
  622.     {
  623.  
  624.     case '\0':
  625.       return;
  626.  
  627.     case 'c':
  628.       val.v_int = ARG_INT (argc, argv);
  629.       break;
  630.  
  631.     case 's':
  632.       val.v_str = ARG_STR (argc, argv);
  633.       break;
  634.  
  635.     case 'd':
  636.     case 'i':
  637.       if (lflag)
  638.         {
  639.           val.v_long = ARG_LONG (argc, argv);
  640.         }
  641.       else
  642.         {
  643.           val.v_int = ARG_INT (argc, argv);
  644.         }
  645.       break;
  646.  
  647.     case 'o':
  648.     case 'x':
  649.     case 'X':
  650.     case 'u':
  651.       if (lflag)
  652.         {
  653.           val.v_ulong = ARG_ULONG (argc, argv);
  654.         }
  655.       else
  656.         {
  657.           val.v_uint = ARG_UINT (argc, argv);
  658.         }
  659.       break;
  660.  
  661.     case 'e':
  662.     case 'E':
  663.     case 'f':
  664.       val.v_double = ARG_DOUBLE (argc, argv);
  665.       break;
  666.  
  667.     default:
  668.       continue;
  669.     }
  670.  
  671.       c = *fmt;
  672.       *fmt = '\0';
  673.  
  674.       if (width != -1 && prec != -1)
  675.     sprintf (str, fstart, width, prec, val);
  676.       else if (width != -1)
  677.     sprintf (str, fstart, width, val);
  678.       else if (prec != -1)
  679.     sprintf (str, fstart, prec, val);
  680.       else
  681.     sprintf (str, fstart, val);
  682.  
  683.       *fmt = c;
  684.  
  685.       obstack_grow (obs, str, strlen (str));
  686.     }
  687.   /* NOTREACHED */
  688. #endif                /* HAVE_EFGCVT */
  689. }
  690.